<?php

class Tree extends Model {
	protected $table_name = 'shouce_tree';

	/**
	 * 增加节点，包括代表的标签ID，节点位置，节点排列
	 * @param parent_id    父节点
	 * @param name    节点名字
	 * 如 1,         1,4,5,
	 * @param sort    排名   大的在前
	 */
	public function addNode($parent_id, $name, $sort=0, $item_id = 0)	{
		if(empty($parent_id)) { //增加根节点  设置路径
			$new_id = $this->insert(array('node_name'=>$name, 'sort'=>$sort));
			$this->update(array('node_id'=>$new_id), array('node_path'=>$new_id.',', 'item_id'=>$item_id));
			return $new_id;
		}
		$new_id = $this->insert(array('parent_id'=>$parent_id, 'node_name'=>$name, 'sort'=>$sort, 'item_id'=>$item_id));
		$parent_node = $this->find(array('node_id'=>$parent_id));
		$node_path = $parent_node['node_path'] . $new_id . ','; 
		$this->update(array('node_id'=>$new_id), array('node_path'=>$node_path));
		return $new_id;
	}
	
	/**
	 * 删除某关联路径
	 * 
	 * @param node_id
	 */
	public function delNode($node_id) {
		$this->delete(array('node_id'=>$node_id));
		//TODO: 关联的删除文章操作
	}

	/**
	 * 输出节点路径的json格式数据
	 * 
	 * @param node_id    节点id
	 */
	public function json($node_id)
	{
	}
	
	/**
	 * 输出所有节点路径的json格式数据
	 */
	public function json_all($open = true) {
		$nodes = $this->select('','node_id,node_name,parent_id', 'sort DESC, node_id ASC');
		$str = '';
		$temp = '';
		if($open) {$temp=',"open":"true"';}
		if(empty($nodes)) return null;
		foreach($nodes as $node){
			if(!empty($str)) $str .= ',';
			$str .= '{"id":' . $node['node_id'] . ',"pId":' . $node['parent_id'] . ',"name":"' . $node['node_name'] .'"'.$temp.'}';
		}
		return '['.$str.']';
	}

	//拖动后设置排序
	public function dropSort($target_id, $parent_id, $sort, $type = 'next') {
		if('next' == $type) { //  设置排序
			$sql = 'update ' . $this->table_name . ' set `sort` = `sort`+1 where `parent_id` =' . $parent_id . ' and `sort` >= '
					 . $sort . ' and `node_id` <=' . $target_id;  
		}else {
			$sql = 'update ' . $this->table_name . ' set `sort` = `sort`-1 where `parent_id` =' . $parent_id . ' and `sort` <= '
				 . $sort . ' and `node_id` >=' . $target_id;
		}
		$this->query($sql); //设置移动后的排序为参照点排序, 参照点在前面(next):当前节点以上的节点排序 +1    或者  参照点在后面(prev):以下的节点的排序-1
	}

	//拖动节点 后的处理
	//treeNodes: [object Object]  targetNode: null  moveType: inner   isCopy:false  
	public function dropNode($treeNodes, $targetNode, $moveType, $isCopy) {
		if(empty($targetNode)) { //特殊处理targetNode为null的时候的初值
			$target['node_path']='';
			$targetNode['id'] = 0;
		}else {
			$target = $this->find(array('node_id'=>$targetNode['id'])); //移动的参照点/目标点
			$target_parent = $this->find(array('node_id'=>$target['parent_id']));
		}
		$pre_node = $this->find(array('node_id'=>$treeNodes[0]['id']));//要移动的点
		
		if('true' === $isCopy) {return $this->addNode($target['parent_id'], $treeNodes[0]['name'], $target['sort']);}//复制节点
		if('next' == $moveType || 'prev' == $moveType) { //移动到目标节点的同级节点下 
			$this->dropSort($target['node_id'], $target['parent_id'], $target['sort'], $moveType);//设置排序
			$this->update(array('node_id'=>$treeNodes[0]['id']), array('parent_id'=>$target['parent_id'],'sort'=>$target['sort']));//记录父节点和排序
			$new_path = $this->combinNodePath($treeNodes[0]['id'],$target_parent['node_path']);//更新本节点的路径
			
		}elseif('inner' == $moveType) {  //移动到内部   不设置排序  完成后要刷新一下
			$this->update(array('node_id'=>$treeNodes[0]['id']), array('parent_id'=>$targetNode['id']));//记录父节点
			$new_path = $this->combinNodePath($treeNodes[0]['id'],$target['node_path']);//更新本节点的路径
		}
		$this->changePathPrefix($pre_node['node_path'], $new_path);//更新以这个节点为父节点有关的点
	}
	
	//由节点id和路径前缀组装路径
	public function combinNodePath($node_id, $prefix_path) {
		$new_path = $prefix_path.$node_id.',';
		$node = $this->find(array('node_id'=>$node_id),'node_path'); //记录更新前的路径
		$this->update(array('node_id'=>$node_id),array('node_path'=>$new_path));
		
		$this->updateItemPath($node['node_path'], $new_path); //	更新相应的记录中的path;
		return $new_path;
	}
	
	//
	public function changePathPrefix($from_pre, $to_pre) {
		if(empty($from_pre)) return;//防止全部替换
		//查找以from_pre为父节点的路径
		$affect_node = $this->query('select * from ' . $this->table_name . ' where `node_path` like "' . $from_pre. '%" and `node_path`!="'.$from_pre.'"');
 		file_put_contents('E:\pro4.log', $this->sql.count($affect_node));
		if(empty($affect_node)) return;
		foreach($affect_node as $node) {
			$from_path = $node['node_path'];
			$to_path = preg_replace('#^'.$from_pre.'#', $to_pre, $from_path);
			$this->update(array('node_id'=>$node['node_id']), array('node_path'=>$to_path));
			
			$this->updateItemPath($from_path, $to_path); //	更新相应的记录中的path;
		}
	}
	
	/****          对应的文章更新  重点            *****/
	//  更新所有的记录中对应的path
	public function updateItemPath($from_path, $to_path) {
		return ;
		//$item_id = $this->getItemIdByPath($from_path);
		//obj('Item')->setItemTableName($item_id);
		//obj('Item')->update(array('node_path'=>$from_path),array('node_path'=>$to_path));
	}
	
	
	//从路径中得到模型id
	public function getItemIdByPath($path) {
		$arr = explode(',', $path);
		foreach($arr as $node_id) {
			$node = $this->find(array('node_id'=>$node_id),'item_id');
			if(!empty($node['item_id'])) return $node['item_id'];
		}
		return false;
	}
	//得到树路径           路径 和文字
	public function getPath($node_id) {
		$nodes = $this->select(array('parent_id'=>$node_id));
		$ret =array();
		foreach ($nodes as $node) {
			//echo $node['node_id'].'   ';
			$res = $this->select(array('parent_id'=>$node['node_id']));
			if(empty($res)) continue;
			$ret = array_merge($ret, $res);
			//$ret += $res;
			//break;
		}
		
		//return $ret;
	}
	
	
	//树id转化为名字. 支持(返回) 字符串/数组
	public function ids2name($ids) {
		if(is_array($ids)) {
			$ret = array();
			foreach($ids as $id) {
				$temp_node = $this->find(array('node_id'=>$id));
				$ret []=$temp_node['node_name'];
			};
			return $ret; //传数组 返回数组
			
		}else {
			$ret = $this->find(array('node_id'=>$ids));
			return @$ret['node_name']; //传字符串  返回字符串
		}
	}
	
	
	//返回数组形式的id,name路径    
	public function getPathById($node_id) {
		$node = $this->find(array('node_id'=>$node_id));
		$ids = explode(',', $node['node_path'],-1);
		$names = $this->ids2name($ids);
		return array('id'=>$ids, 'name'=>$names);
	}
	
	public function getNoteById($node_id, $link = '--', $cycle = 0) {
		static $ret = array();
		$res = $this->select(array('parent_id'=>$node_id),'','sort DESC, node_id ASC');
		if(empty($res)) return array();
		$cycle++;
		foreach($res as $node) {
			$ret += array($node['node_path']=>str_repeat($link,$cycle).$node['node_name']);
			$this->getNoteById($node['node_id'], $link, $cycle);
		}
		return $ret;
	}
	
	
	/*递归输出 路径  为配合getPathByItem而写
	 * $link 为连接符号
	 * $cycle 为第几级目录
	 */
	public function getAllPathById($node_id, $link = '--', $cycle = 0) {
		static $ret = array();
		$res = $this->select(array('parent_id'=>$node_id),'','sort DESC, node_id ASC');
		if(empty($res)) {return array();}
		$cycle++;
		foreach($res as $node) {
			$ret += array($node['node_path']=>str_repeat($link,$cycle).$node['node_name']);
			$this->getAllPathById($node['node_id'], $link, $cycle);
		}
		return $ret;
	}
	
	//列出与某个item相关的树形
	public function getPathByItem($item_name='', $link = '--') {
		$node = $this->find(array('node_name'=>$item_name),'node_id');
		if(empty($node)) $node['node_id'] = 0;
		$res = $this->getAllPathById($node['node_id'], $link);
		return array($node['node_id'] . ','=>$item_name) + $res;
	}
	
	public function getAllNoteById($node_id, $link = '--', $cycle = 0) {
		static $ret = array();
		$res = $this->select(array('parent_id'=>$node_id),'','sort DESC, node_id ASC');
		if(empty($res)) {return array();}
		$cycle++;
		foreach($res as $node) {
			$ret += array($node['node_note']=>str_repeat($link,$cycle).$node['node_name']);
			$this->getAllNoteById($node['node_id'], $link, $cycle);
		}
		return $ret;
	}
	
	//列出与某个item相关的树形
	public function getNoteByItem($item_name='', $link = '--') {
		$node = $this->find(array('node_name'=>$item_name),'node_id,node_note');
		if(empty($node)) {
			$node['node_id'] = 0;
			$node['node_note'] = ''; 
		}
		$res = $this->getAllNoteById($node['node_id'], $link);
		return array($node['node_note']=>$item_name) + $res;
	}
	
	
	public function getChildById($id) {
		return $this->select(array('parent_id'=>$id), '', 'sort DESC, node_id ASC');
	}
	
	public function getChildByName($name) {
		$node = $this->find(array('node_name'=>$name),'node_id');
		return $this->getChildById($node['node_id']);
	}
	
	/**
	 * 列出某节点路径中是否含有模型
	 * @param node_id
	 * @return true / false
	 */
	public function hasItem($node_id) {
		$node = $this->find(array('node_id'=>$node_id));
		$node_ids = explode(',', $node['node_path']);
		foreach($node_ids as $id) {  //遍历节点, 判断节点是否有模型字段的定义  有则返回true
			if($this->isItem($id)) return true;
		}
		return false;
	}
	
	//判断某个树节点是不是对应模型
	public function isItem($node_id) {
		$ret = $this->find(array('node_id'=>$node_id));
		if(!empty($ret['item_id'])) return true;
		return false;
	}
	
	public function get_tree_by_name($node_name) {
		// $ret = $this->find(array('node_id'=>$node_id));
		// if(!empty($ret['item_id'])) return true;
		return false;
	}
	
	
	
	
}
?>